package top.leyi.ServiceImpl;

import top.leyi.RunnableImpl.CommentRunnableImpl;
import top.leyi.RunnableImpl.TalkRunnableImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import top.leyi.IService.ITalkService;
import top.leyi.dao.AsyncStorageData;
import top.leyi.entity.ObjRedisTemplate;
import top.leyi.entity.SQLUtil;
import top.leyi.entity.Talk.SimpleComment;
import top.leyi.entity.Talk.SimpleTalk;
import top.leyi.entity.Talk.Talk;
import top.leyi.entity.pushAndColle.Push;
import top.leyi.entity.user.User;
import top.leyi.exception.IllegalDeleteException;
import top.leyi.exception.TalkNotFoundException;
import top.leyi.mapper.*;

import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
     *@ThreadSafe
     * @algh
     * 将pos作为redis中talk的主键，这个值必须与mysql中的主键一致
     */

@Service
public class TalkServiceImpl implements ITalkService {

    @Autowired 
    StringRedisTemplate redisTemplate;
    @Autowired
    ObjRedisTemplate objRedisTemplate;
    @Autowired
    AsyncStorageData asyncStorageData;
    @Autowired
    TalkRunnableImpl talkRunnable;
    @Autowired
    CommentRunnableImpl commentRunnable;
    @Autowired
    TalkMapper talkMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    PushMapper pushMapper;
    @Autowired
    AttenMapper attenMapper;
    @Autowired
    CollectionMapper collectionMapper;
    public static  final Object lock = new Object();

    public static  final Object listLock = new Object();


    @Override
    public List<SimpleTalk>   getTalks(int offset, int userId, String key) {

        List<SimpleTalk>  result = new ArrayList<>();
        if(result.size() == 0){
         /*
           从mysql中查找
         */
            result.clear();
            SQLUtil util = new SQLUtil();
            util.setOffset((offset - 1)*LIMIT);
            util.setLimit(LIMIT);
            util.setKey(key);
            result = talkMapper.fuzzyQueryTalks(util);
            for( Object object : result){
                SimpleTalk t =   (SimpleTalk) object;
                t.setTalks(talkMapper.queryComments(t.getId() + ""));

                Talk tt = new Talk();
                tt.setId(t.getId());
                tt.setUser_id(userId);
                String state = talkMapper.queryGoodState(tt);
                t.setLike(state != null && state.equals("1"));
                ///查询是否被收集
                Integer collectedId = collectionMapper.queryHasCol(t.getId(), userId);
                if(collectedId != null ) {
                    t.setCollectedId(collectedId);
                    t.setCollected(true);
                 }
                t.setLikes(talkMapper.queryLikes(t.getId()));
            }
        }
        return result;
    }

    @Override
    public List getHistoryTalks(int offset, int userId, String key) {

        List<SimpleTalk>  result = new ArrayList<>();

        if(result.size() == 0){
         /*
           从mysql中查找
         */
            result.clear();
            SQLUtil util = new SQLUtil();
            util.setOffset((offset - 1)*LIMIT);
            util.setLimit(LIMIT);
            util.setKey(key);
            util.setId(userId);
            result = talkMapper.fuzzyQueryHisTalks(util);
            for( Object object : result){
                SimpleTalk t =   (SimpleTalk) object;
                t.setTalks(talkMapper.queryComments(t.getId() + ""));

                Talk tt = new Talk();
                tt.setId(t.getId());
                tt.setUser_id(userId);
                String state = talkMapper.queryGoodState(tt);
                t.setLike(state != null && state.equals("1"));
                ///查询是否被收集
                Integer collectedId = collectionMapper.queryHasCol(t.getId(), userId);
                if(collectedId != null) {
                    t.setCollectedId(collectedId );
                    t.setCollected(true);
                }
                t.setLikes(talkMapper.queryLikes(t.getId()));
            }
        }
        return result;
    }

    /**
     * 获取热门的说说
     * @return
     */
    public List  getHotTalks( int userId){

        Set<String> set = redisTemplate.opsForZSet().range("hotTalk", 0, -1);
        List result = new ArrayList();
        set.forEach((item)->{
            SimpleTalk t =   (SimpleTalk) objRedisTemplate.opsForHash().get("talk:"+item,"talk");
            //如果说说不存在则直接返回
            if(t == null) {
                return;
            }
            Integer collectedId = collectionMapper.queryHasCol(t.getId(), userId);
            if(collectedId != null ) {
                t.setCollectedId(collectedId);
                t.setCollected(true);
            }
            Integer vote = (Integer) objRedisTemplate.opsForHash().get("talk:"+item,"vote");

            Set<String> voteUser = redisTemplate.opsForSet().members("vote:"+vote);
            t.setLikes(voteUser.size());
            voteUser.forEach((i)->{
                if(i.endsWith(":" + userId)) {
                    t.setLike(true);
                }
            });
            result.add( t);
        });
         return result;
    };

    @Override
    public Talk getTalkWithId(int talkId, User user) {
        SimpleTalk t =    talkMapper.getTalkWithId(talkId);
        t.setTalks(talkMapper.queryComments(t.getId() + ""));

        Talk tt = new Talk();
        tt.setId(t.getId());
        tt.setUser_id(user.getId());
        String state = talkMapper.queryGoodState(tt);

        t.setLike(state != null && state.equals("1"));
        ///查询是否被收集
        Integer collectedId = collectionMapper.queryHasCol(t.getId(), user.getId());
        if(collectedId != null ) {
            t.setCollectedId(collectedId);
            t.setCollected(true);
        }
        t.setLikes(talkMapper.queryLikes(t.getId()));

        return t;
    }

    /**
         * 添加动态
         * @param talk
         * @return
         * @ThreadSafe
         */

    @Override
    public Talk addTalk(Talk talk, User user){

        talk.setUser(user);
        talkMapper.addTalk(talk);
        /*
         * 发布者为大v，因此要将此条说说通知给所有他的粉丝
         */
        talk  = talkMapper.getRencentlyTalk(user.getId());

        List<User> fansList = attenMapper.queryAllFans(user.getId());

        for(User user1 : fansList) {
            Push push = new Push();
            push.setOriginal(talk.getId());
            push.setDest(user1.getId());
            push.setType("关注");
            pushMapper.addPush(push);
        }
        return  talk;
    }

        /**
         * 评论一个说说
         * @param
         * @param comment
         * @return
         */
    @Override
    public Talk commentTalk(Talk comment, User user) throws TalkNotFoundException {

            int userId = comment.getUser_id();
            comment.setUser(user);

            String id = comment.getId() + "";
            /*
             * 先在redis中查有没有这条数据
             */
            Talk oldTalk = null;

            oldTalk = (SimpleTalk) objRedisTemplate.opsForHash().get("talk:"+id,"talk");

            if(oldTalk != null){

                oldTalk.addTalk(comment);
                objRedisTemplate.opsForHash().put("talk:"+id,"talk", oldTalk);
            }

            else  {
                oldTalk = talkMapper.queryOneTalk(id);
                if(oldTalk == null){
                    throw new TalkNotFoundException();
                }
                oldTalk.setTalks(talkMapper.queryComments(oldTalk.getId() + ""));
                oldTalk.addTalk(comment);
            }

            /*
              将评论存储到mysql中
             */
              talkMapper.addComment(comment);

              /*
              * 将评论添加到通知中
               */
             Push push = new Push();
             push.setOriginal(oldTalk.getId());
             push.setDest(oldTalk.getUser_id());
             push.setType("评论");
             pushMapper.addPush(push);
             return  oldTalk;
    }

          /*
           检查list的长度,如果大于 MAX_SIZE_LIMIT 则对其进行裁剪， 裁剪为  MAX_SIZE
          */
    private void listSizeCheck(){
        long nums = 0;
        nums = objRedisTemplate.opsForList().size("talkList");
        if(nums >= MAX_SIZE_LIMIT){
            synchronized (listLock){
                ///双重检查锁
                if((nums = objRedisTemplate.opsForList().size("talkList")) >= MAX_SIZE_LIMIT){
                    while(nums-- > MAX_SIZE){
                        String key = redisTemplate.opsForList().rightPop("talkList");
                        objRedisTemplate.opsForHash().delete("talkMap", key);
                    }
                }
            }
        }
    }

        @Override
        public void goodTalk(Talk talk, User user) throws  TalkNotFoundException{
            Lock lock = new ReentrantLock();
            int UserId = user.getId();
            String id = talk.getId() + "";
            /*
             * 先在redis中查有没有这条数据
             */
            Talk oldTalk = null;

            oldTalk =  (SimpleTalk) objRedisTemplate.opsForHash().get("talk:"+id,"talk");

            if(oldTalk != null){
                int vote = (Integer)objRedisTemplate.opsForHash().get("talk:"+id,"vote");
                Set<String> set = redisTemplate.opsForSet().members("vote:"+id);

                Iterator iterator = set.iterator();
                boolean flag = false;
                while (iterator.hasNext()) {
                 String userId = (String)iterator.next();
                 if(userId.endsWith(":" + UserId)) {
                     redisTemplate.opsForSet().remove("vote:"+id, userId);
                     flag = true;
                 }
                }
                 if(!flag) {
                     redisTemplate.opsForSet().add("vote:"+id,"user:"+UserId);
                 }

            }

            else  {
                oldTalk = talkMapper.queryOneTalk(id);
                if(oldTalk == null)
                throw new TalkNotFoundException();
            }

           /*
             在数据库中的操作
            */
            String state =  talkMapper.queryGoodState(talk);

            if(state == null){
                talkMapper.addGood(talk);
            }
            else {
                if (state.equals("0")){
                    talkMapper.setGoodTrue(talk);
                }
                else {
                    talkMapper.setGoodFalse(talk);
                }
            }

            if(!"1".equals(state)) {

                /*
                 * 将评论添加到通知中
                 */
                Push push = new Push();
                push.setOriginal(oldTalk.getId());
                push.setDest(oldTalk.getUser_id());
                push.setType("点赞");
                pushMapper.addPush(push);
            }
        }

    @Override
    public void deleteTalk(Talk talk ) throws TalkNotFoundException  {

        /*在redis中删除缓存
        1 删除zset
        2 删除key
         */

        redisTemplate.opsForZSet().remove("hotTalk",talk.getId()+"");
        Talk oldTalk =  (SimpleTalk) objRedisTemplate.opsForHash().get("talk:"+talk.getId(),"talk");
        if(oldTalk != null) {
            objRedisTemplate.delete("talk:"+talk.getId());
        }
            talkMapper.deleteOneTalk(talk.getId());
    }

    @Override
    public void deleteComment(Talk talk) throws TalkNotFoundException {

        int talkId = talkMapper.queryCommenTalkId(talk.getId());
        Talk oldTalk =  (SimpleTalk) objRedisTemplate.opsForHash().get("talk:"+talkId,"talk");
        ///如果在redis中查询到了这条数据

        if(oldTalk != null) {
            List<Talk> talks = oldTalk.getTalks();
            for(Talk talk1 : talks) {
                if(talk1.getId() == talk.getId()) {
                    talks.remove(talk1);
                }
            }
        objRedisTemplate.opsForHash().put("talk:"+talkId,"talk", oldTalk);
        }
        ///在mysql中删除评论
        talkMapper.deleteOneTalkComment(talk.getId());
    }
}
